package org.jplcc.memory;

import java.util.Date;

import org.jplcc.Connection;
import org.jplcc.JPLCCException;
import org.jplcc.PLCMetadata;

class MemoryConnection implements Connection {
	private MemoryMap memoryMap;

	MemoryConnection(MemoryMap memoryMap) {
		this.memoryMap = memoryMap;
	}

	@Override
	public void close() throws JPLCCException {
		this.memoryMap = null;
	}

	@Override
	public boolean isClosed() throws JPLCCException {
		return this.memoryMap == null;
	}

	private void connectionValidation() throws JPLCCException {
		if (isClosed()) {
			throw new JPLCCException("This connection is closed.");
		}
	}

	@Override
	public PLCMetadata getMetaData() throws JPLCCException {
		connectionValidation();
		return new MemoryPLCMetadata(this);
	}

	@Override
	public boolean readBool(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (Boolean) memoryMap.get(tag);
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public boolean[] readBools(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (boolean[]) ((boolean[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public byte readByte(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (Byte) memoryMap.get(tag);
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public byte[] readBytes(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (byte[]) ((byte[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public Date readDate(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (Date) ((Date) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public Date[] readDates(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (Date[]) ((Date[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public double readDouble(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (Double) memoryMap.get(tag);
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public double[] readDoubles(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (double[]) ((double[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public float readFloat(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (Float) memoryMap.get(tag);
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public float[] readFloats(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (float[]) ((float[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public int readInteger(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (Integer) memoryMap.get(tag);
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public int[] readIntegers(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (int[]) ((int[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public long readLong(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (Long) memoryMap.get(tag);
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public long[] readLongs(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (long[]) ((long[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public short readShort(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (Short) memoryMap.get(tag);
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public short[] readShorts(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (short[]) ((short[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public String readString(String tag) throws JPLCCException {
		connectionValidation();
		try {
			return (String) memoryMap.get(tag);
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	@Override
	public String[] readStrings(String tag, int length) throws JPLCCException {
		connectionValidation();
		try {
			return (String[]) ((String[]) memoryMap.get(tag)).clone();
		} catch (ClassCastException e) {
			throw new JPLCCException(createWrongTypeMessage(e));
		}
	}

	private String createWrongTypeMessage(ClassCastException e) {
		return "Wrong type: " + e.getMessage();
	}

	@Override
	public void writeBool(String tag, boolean value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value);
	}

	@Override
	public void writeBools(String tag, boolean[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeByte(String tag, byte value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value);
	}

	@Override
	public void writeBytes(String tag, byte[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeDate(String tag, Date value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeDates(String tag, Date[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeDouble(String tag, double value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value);
	}

	@Override
	public void writeDoubles(String tag, double[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeFloat(String tag, float value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value);
	}

	@Override
	public void writeFloats(String tag, float[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeInteger(String tag, int value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value);
	}

	@Override
	public void writeIntegers(String tag, int[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeLong(String tag, long value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value);
	}

	@Override
	public void writeLongs(String tag, long[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeShort(String tag, short value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value);
	}

	@Override
	public void writeShorts(String tag, short[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}

	@Override
	public void writeString(String tag, String value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value);
	}

	@Override
	public void writeStrings(String tag, String[] value) throws JPLCCException {
		connectionValidation();
		memoryMap.put(tag, value.clone());
	}
}
